/**
 * @file duration_recorder.hpp
 * Basic perf counter that records time duration
 */

#pragma once

#include <vector>
#include <chrono>
#include <filesystem>
#include <fstream>


namespace gestalt {
namespace perf {

using namespace std;

/**
 * time duration recorder
 *
 * `tick()` before, `tock()` after
 *
 * @tparam Dur std::chrono::duration
 */
template <typename Dur = std::chrono::microseconds>
struct BasicDurationRecorder {
    using duration_type = Dur;
    mutable std::vector<duration_type> records;

public:
    BasicDurationRecorder() : records(), last_start()
    {
        records.reserve(1e5);
    }

private:
    using clock_type = std::chrono::steady_clock;
    clock_type::time_point last_start;
public:
    /**
     * start a duration
     *
     * Later invocation will overwrite previous ones.
     */
    inline void tick()
    {
        last_start = clock_type::now();
    }
    /**
     * end and record a duration
     *
     * If there were multiple `tick()`s, only the latest `tick()` is valid and
     * answered.
     */
    inline void tock()
    {
        const auto current = clock_type::now();
        records.push_back(std::chrono::duration_cast<duration_type>(current - last_start));
    }

public:
    /**
     * dumps recorded latency in CSV format
     *
     * Since we only record latency number, it is just header "latency" followed
     * by a list of numbers, each on its own line
     * @param out path to output file
     */
    void dump(const filesystem::path &out) const
    {
        ofstream f(out);
        f << "latency(us)\n";
        for (const auto &d : records)
            f << d.count() << "\n";
        f << std::flush;
    }
};  /* class BasicDurationRecorder */

}   /* namespace perf */
}   /* namespace gestalt */
